#!/bin/bash

function InitRancher(){
    user_set_passwd=$1
    init_password=$2
    eip_access=$3

    set_cookie=$(curl -s -vvv -k --location --request POST --X POST 'https://127.0.0.1:30443/v3-public/localProviders/local?action=login' \
    --header 'User-Agent: Apipost client Runtime/+https://www.apipost.cn/' \
    --header 'Content-Type: application/json' \
    --data "{
	    \"description\": \"UI session\",
    	\"responseType\": \"cookie\",
	    \"username\": \"admin\",
    	\"password\": \"$init_password\"
    }" 2>&1 | grep Set-Cookie |awk '{print $3}')

    while true
    do
        set_cookie=$(curl -s -vvv -k --location --request POST --X POST 'https://127.0.0.1:30443/v3-public/localProviders/local?action=login' \
            --header 'User-Agent: Apipost client Runtime/+https://www.apipost.cn/' \
            --header 'Content-Type: application/json' \
            --data "{
	            \"description\": \"UI session\",
    	        \"responseType\": \"cookie\",
	            \"username\": \"admin\",
    	        \"password\": \"$init_password\"
            }" 2>&1 | grep Set-Cookie |awk '{print $3}')
        if [ -z "$set_cookie" ];then
            sleep 5
        else
            break
        fi
    done 

    while true
    do
        user_id=$(curl -s -k --location --request GET --X GET 'https://127.0.0.1:30443/v3/users?limit=0' \
                    --header "cookie: R_USERNAME=admin; R_PCS=light; R_REDIRECTED=true; R_LOCALE=zh-hans; CSRF=707dc03aed; $set_cookie" | awk -F "user-" '{print $2}' |cut -c1-5 ) 
        if [ -z "$user_id" ];then
            sleep 5
        else
            break
        fi
    done

        while true
    do
        set_password=$(curl -s -k --location --request POST --X POST "https://127.0.0.1:30443/v3/users/user-$user_id?action=setpassword" \
            --header "cookie: R_USERNAME=admin; R_PCS=light; R_REDIRECTED=true; R_LOCALE=zh-hans; CSRF=707dc03aed; $set_cookie" \
            --header 'Content-Type: application/json' \
            --data "{\"newPassword\":\"$user_set_passwd\"}")
        if [ -z "$set_password" ];then
            sleep 5
        else
            break
        fi
    done

    while true
    do
        server_url_json=$(curl -s -k --location --request GET --X GET 'https://127.0.0.1:30443/v1/management.cattle.io.settings/server-url' \
            --header "cookie: R_USERNAME=admin; R_PCS=light; R_REDIRECTED=true; R_LOCALE=zh-hans; CSRF=707dc03aed; $set_cookie")
        if [ -z "$server_url_json" ];then
            sleep 5
        else
            break
        fi
    done

    curl -s -k --location --request PUT --X PUT 'https://127.0.0.1:30443/v1/management.cattle.io.settings/server-url' \
    --header "cookie: R_USERNAME=admin; R_PCS=light; R_REDIRECTED=true; R_LOCALE=zh-hans; CSRF=707dc03aed; $set_cookie" \
    --header 'Content-Type: application/json' \
    --data "${server_url_json/\"value\":\"\"/\"value\":\"https://$eip_access\"}"
}

function DeployKubernetes(){
    MasterServer1=$1
    MasterServer2=$2
    MasterServer3=$3

    while true
    do
        rke_file=$(wget https://rancher-autoinstall-20220606.oss-cn-hangzhou.aliyuncs.com/rke_v1.3.11 -O /tmp/rke)
        rke_file_status=$(ls /tmp/rke)
        if [ -z "$rke_file_status" ];then
            sleep 5
        else
            chmod +x /tmp/rke && cp /tmp/rke /usr/bin/rke
            break
        fi
    done

    echo "nodes:
  - address: $MasterServer1
    user: rancher
    role: [controlplane,etcd,worker]
    ssh_key_path: ~/.ssh/id_rsa
  - address: $MasterServer2
    user: rancher
    role: [controlplane,etcd,worker]
    ssh_key_path: ~/.ssh/id_rsa
  - address: $MasterServer3
    user: rancher
    role: [controlplane,etcd,worker]
    ssh_key_path: ~/.ssh/id_rsa
services:
  etcd:
    backup_config:
      enabled: true
      interval_hours: 6
      retention: 8
    snapshot: true
    creation: 5m0s
    retention: 24h
    # 修改空间配额为$((6*1024*1024*1024))，默认2G,最大8G
    extra_args:
      quota-backend-bytes: \"6442450944\"
      auto-compaction-retention: 240 #(单位小时)
  kube-api:
    extra_args:
      watch-cache: true
      default-watch-cache-size: 1500
      # 默认值400，设置0为不限制，一般来说，每25~30个Pod有15个并行
      max-requests-inflight: 800
      # 默认值200，设置0为不限制
      max-mutating-requests-inflight: 400
  kube-controller:
    extra_args:
      # 修改每个节点子网大小(cidr掩码长度)，默认为24，可用IP为254个；23，可用IP为510个；22，可用IP为1022个；
      node-cidr-mask-size: \"24\"
      node-monitor-period: \"5s\"
      ## 当节点通信失败后，再等一段时间kubernetes判定节点为notready状态。
      ## 这个时间段必须是kubelet的nodeStatusUpdateFrequency(默认10s)的整数倍，
      ## 其中N表示允许kubelet同步节点状态的重试次数，默认40s。
      node-monitor-grace-period: \"20s\"
      ## 再持续通信失败一段时间后，kubernetes判定节点为unhealthy状态，默认1m0s。
      node-startup-grace-period: \"30s\"
      ## 再持续失联一段时间，kubernetes开始迁移失联节点的Pod，默认5m0s。
      pod-eviction-timeout: \"1m\"
      # 默认20. 同时同步的垃圾收集器工作器的数量。
      concurrent-gc-syncs: 20
      # 默认10. 同时同步的命名空间的数量。
      concurrent-namespace-syncs: 10
      # 默认5. 同时同步的副本集的数量。
      concurrent-replicaset-syncs: 5
      # 默认1. 同时同步的服务数。
      concurrent-service-syncs: 1
      # 默认5. 同时同步的服务帐户令牌数。
      concurrent-serviceaccount-token-syncs: 5
      # 默认30s. 同步deployment的周期。
    deployment-controller-sync-period: 30s
    # 默认15s。同步PV和PVC的周期。
    pvclaimbinder-sync-period: 15s
    # 默认20. 与kubernetes apiserver交谈时使用的QPS，QPS = 并发量 / 平均响应时间
    kube-api-qps: 40
  kubelet:
    extra_args:
      # 传递给网络插件的MTU值，以覆盖默认值，设置为0(零)则使用默认的1460
      network-plugin-mtu: \"1500\"
      # 修改节点最大Pod数量
      max-pods: \"200\"
      # 密文和配置映射同步时间，默认1分钟
      sync-frequency: \"3s\"
      # Kubelet进程可以打开的文件数（默认1000000）,根据节点配置情况调整
      max-open-files: \"2000000\"
      # kubelet默认一次拉取一个镜像，设置为false可以同时拉取多个镜像，
      # 前提是存储驱动要为overlay2，对应的Dokcer也需要增加下载并发数，参考[docker配置](/rancher2x/install-prepare/best-practices/docker/)
      serialize-image-pulls: \"false\"
      # 拉取镜像的最大并发数，registry-burst不能超过registry-qps。
      # 仅当registry-qps大于0(零)时生效，(默认10)。如果registry -qps为0则不限制(默认5)。
      registry-burst: \"10\"
      registry-qps: \"0\"
      cgroups-per-qos: \"true\"
      cgroup-driver: \"cgroupfs\"
      # 节点资源预留
      enforce-node-allocatable: \"pods\"
      system-reserved: \"cpu=0.25,memory=200Mi\"
      kube-reserved: \"cpu=0.25,memory=1500Mi\"
      # POD驱逐，这个参数只支持内存和磁盘。
      ## 硬驱逐伐值
      ### 当节点上的可用资源降至保留值以下时，就会触发强制驱逐。强制驱逐会强制kill掉POD，不会等POD自动退出。
      eviction-hard: \"memory.available<300Mi,nodefs.available<10%,imagefs.available<15%,nodefs.inodesFree<5%\"
      ## 软驱逐伐值
      ### 以下四个参数配套使用，当节点上的可用资源少于这个值时但大于硬驱逐伐值时候，会等待eviction-soft-grace-period设置的时长；
      ### 等待中每10s检查一次，当最后一次检查还触发了软驱逐伐值就会开始驱逐，驱逐不会直接Kill POD，先发送停止信号给POD，然后等待eviction-max-pod-grace-period设置的时长；
      ### 在eviction-max-pod-grace-period时长之后，如果POD还未退出则发送强制kill POD\"
      eviction-soft: \"memory.available<500Mi,nodefs.available<50%,imagefs.available<50%,nodefs.inodesFree<10%\"
      eviction-soft-grace-period: \"memory.available=1m30s,nodefs.available=1m30s,imagefs.available=1m30s,nodefs.inodesFree=1m30s\"
      eviction-max-pod-grace-period: \"30\"
      eviction-pressure-transition-period: \"30s\"
    extra_binds:
      - \"/usr/libexec/kubernetes/kubelet-plugins:/usr/libexec/kubernetes/kubelet-plugins\"
bernetes_version: v1.22.9-rancher1-1" > /root/cluster.yml

    rke_cluster_install=$(rke up --config /root/cluster.yml |grep level=fatal)
    sleep 30

    docker cp kubelet:/usr/local/bin/kubectl /usr/local/bin/kubectl
    mkdir ~/.kube/
    /usr/bin/cp kube_config_cluster.yml ~/.kube/config

    while true
    do
        if [ -z "$rke_cluster_install" ];then
            rke_cluster_status=$(kubectl get node | grep -v "NAME\|NotReady")
            if [ -z "$rke_cluster_status" ];then
                sleep 5
            else
                echo 'deploy k8s cluster successfully' >> /tmp/rancher-install.log
                break
            fi
        else
            echo $rke_cluster_install >> /tmp/rancher-install.log
            rke remove --force
            sleep 10
            rke_cluster_install=$(rke up --config /root/cluster.yml |grep level=fatal)
            /usr/bin/cp kube_config_cluster.yml ~/.kube/config
        fi
    done
}

function DeployRancher(){
    # coding 

    RANCHER_ADMIN_PD=$4
    ACCESS_EIP=$5

    MasterServer1=$1
    MasterServer2=$2
    MasterServer3=$3

    # install helm
    while true
    do
        helm_file=$(wget https://rancher-autoinstall-20220606.oss-cn-hangzhou.aliyuncs.com/helm-v3.9.0-linux-amd64.tar.gz)
        helm_file_status=$(ls |grep helm-v3.9.0-linux-amd64.tar.gz)
        if [ -z "$helm_file_status" ];then
            sleep 5
        else
            tar xvf helm-v3.9.0-linux-amd64.tar.gz
            cp linux-amd64/helm /usr/bin/helm
            break
        fi
    done

    while true
    do
        git_install=$(yum install git -y)
        git_install_status=$(git verison | grep "git version")
        rancher_chart_file=$(git clone -b v2.5.5 https://gitee.com/rancher/server-chart.git)
        rancher_chart_file_status=$(ls server-chart)
        rancher_pandaria_charts=$(wget https://rancher-autoinstall-20220606.oss-cn-hangzhou.aliyuncs.com/rancher-2.6.5-ent.tgz)
        rancher_pandaria_charts_status=$(ls rancher-2.6.5-ent.tgz)
        if [ -z "$rancher_chart_file_status" ] && [ -z "$git_install_status" ] && [ -z "$rancher_pandaria_charts_status" ];then
            sleep 5
        else
            sed -i 's/kubeVersion: < 1.20.0-0/kubeVersion: < 1.24.0-0/g' server-chart/rancher/Chart.yaml

            bash server-chart/create_self-signed-cert.sh --ssl-trusted-ip=$ACCESS_EIP,$MasterServer1,$MasterServer1,$MasterServer1,127.0.0.1 --ssl-size=2048 --ssl-date=3650

            kubectl create namespace cattle-system
            kubectl -n cattle-system create secret tls tls-rancher-ingress --cert=./tls.crt --key=./tls.key;
            kubectl -n cattle-system create secret generic tls-ca --from-file=cacerts.pem;
            helm install rancher \
              --namespace cattle-system \
              --set rancherImage=rancher/rancher \
              --set rancherImageTag=v2.6.5 \
              --set service.type=NodePort \
              --set service.ports.nodePort=30443 \
              --set privateCA=true \
              --set useBundledSystemChart=true \
              --set ingress.tls.source=secret \
              rancher-2.6.5-ent.tgz
            sleep 180
            break
        fi
    done

    while true
    do
        RANCHER_INIT_PASSWD=$(kubectl get secret --namespace cattle-system bootstrap-secret -o go-template='{{.data.bootstrapPassword|base64decode}}{{"\n"}}')  
        if [ -z "$RANCHER_INIT_PASSWD" ];then
            sleep 5
        else
            InitRancher $RANCHER_ADMIN_PD $RANCHER_INIT_PASSWD $ACCESS_EIP
            break
        fi
    done
}

function Init_Node(){

    install_expect=$(yum install expect -y)

    if [ $DEBUG_MODE ];then
        echo $install_expect >> /tmp/rancher-install.log
    fi

    node_list="$MasterServer1 $MasterServer2 $MasterServer3"

    for i in $node_list;
    do
        ssh root@$i "wget https://rancher-autoinstall-20220606.oss-cn-hangzhou.aliyuncs.com/os-configure.sh -O /root/os-configure.sh"
        ssh root@$i "bash /root/os-configure.sh"
        ssh root@$i "mkdir -p /home/rancher/.ssh ; cp /root/.ssh/* /home/rancher/.ssh/ ;chown rancher:root /home/rancher/.ssh/authorized_keys"
    done

    DeployKubernetes $MasterServer1 $MasterServer2 $MasterServer3
    DeployRancher $MasterServer1 $MasterServer2 $MasterServer3 $RANCHER_ADMIN_PD $ACCESS_EIP
}

usage () {
    echo "USAGE: $0 [-h|--help] 显示帮助信息"
    echo '  [--admin-password text] rancher admin 用户密码,长度需要在12至32位之间.'
    echo '  [--node-password text] 节点 root 用户密码.'
    echo '  [--access-ip ip] rancher 负载均衡器地址.'
    echo '  [--rancher-node1 ip] rancher local集群 master1 节点.'
    echo '  [--rancher-node2 ip] rancher local集群 master2 节点.'
    echo '  [--rancher-node3 ip] rancher local集群 master3 节点.'
    echo '  [--local-ip] rancher local集群 master1 节点使用本机IP;设置此参数时不可设置 --rancher-node1 参数.'
    echo '  [--debug] 查看更多的日志，输出至 /tmp/rancher-install.log .'
    echo '  使用示例: '
    echo '  bash create-ha-rancher.sh --admin-password xxx --node-password xxx --access-ip 1.1.1.1 \ '
    echo '    --rancher-node1 2.2.2.2 --rancher-node2 3.3.3.3 --rancher-node3 4.4.4.4'
}

while [[ $# -gt 0 ]]; do
    key="$1"
    case $key in
        --admin-password)
        RANCHER_ADMIN_PD="$2"
        shift # past argument
        shift # past value
        ;;
        --access-ip)
        ACCESS_EIP="$2"
        shift # past argument
        shift # past value
        ;;
        --node-password)
        NODE_PASSWD="$2"
        shift # past argument
        shift # past value
        ;;
        --rancher-node1)
        MasterServer1="$2"
        shift # past argument
        shift # past value
        ;;
        --rancher-node2)
        MasterServer2="$2"
        shift # past argument
        shift # past value
        ;;
        --rancher-node3)
        MasterServer3="$2"
        shift # past argument
        shift # past value
        ;;
        --local-ip)
        LocalIP="true"
        shift # past argument
        ;;
        --debug)
        DEBUG_MODE="true"
        shift # past argument
        ;;
        -h|--help)
        help="true"
        shift
        ;;
        *)
        usage
        exit 1
        ;;
    esac
done

if [[ $help ]]; then
    usage
    exit 0
fi

if $LocalIP;then

    route_gateway=$(route -n|grep -v Kernel|awk '{print $2}')
    gateway_number=2
    for i in $route_gateway
    do
        gateway_value=$(echo $i | grep -v "Gateway\|0.0.0.0")
        if [ -z "$gateway_value" ];then
            gateway_number=$[ $gateway_number + 1 ]
        else
            MasterServer1=`ifconfig $(route -n | awk "NR==$gateway_number" |awk '{print $8}') | grep -w inet |awk '{print $2}'`
            break
        fi
    done
fi

EXEPECT_INSTALL=$(yum install expect -y 2&>1)

if [ $DEBUG_MODE ];then
    echo $EXEPECT_INSTALL
fi

NODE_LIST="$MasterServer1 $MasterServer2 $MasterServer3"

while true
do

    for i in $NODE_LIST
    do
        node_status=$(curl -s --connect-timeout 3 $i:22 |grep OpenSSH)
        node_status_sum="$node_status_sum $node_status"
    done

    node_status_sum_status=$(echo $node_status_sum |wc -w)

    if [ $node_status_sum_status -eq 3 ];then
        break
    else
        echo "wait node running" > /tmp/rancher-install.log
    fi

done

if [ ! -f ~/.ssh/id_rsa ];then
 ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
else
 echo "id_rsa has created ..."
fi

for ip in $NODE_LIST
  do
    expect <<EOF
      set timeout 10
      spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@$ip
      expect {
        "yes/no" { send "yes\n";exp_continue }
        "password" { send "$NODE_PASSWD\n" }
      }
     expect "password" { send "$NODE_PASSWD\n" }
EOF
  done

Init_Node